﻿#include "pch.h"
#if _QG_ENABLE_WIDGET
#include "qgp/qgach.h"
#include "qgp/qgaud.h"
#include "qgp/qguwgs.h"

//////////////////////////////////////////////////////////////////////////
// 패널
KIMPL_SUBCLASS(qwPanel, "WidgetPanel");

//
qwPanel::qwPanel(qgWidgetType type /*= QGW_PANEL*/)
	: super_type(type)
	, _depth(0)
{
	_insts.fill = true;
	_insts.input = true;
	_insts.ctnr = true;
	_insts.border = true;

	_bg.visible = true;
}

//
qwPanel::~qwPanel()
{
	ClearControls();

	kobj_unload(_bg.tex);
}

void qwPanel::OnInitialize()
{
	super_type::OnInitialize();

	_bg.res = _shed->GetResource(QGWELM_PANEL_BACKGROUND);
}

//
bool qwPanel::OnUpdate(float adv)
{
	bool childrefresh;

	BuildBound();

	if (!NeedRefresh())
		childrefresh = false;
	else
	{
		childrefresh = true;
		ResetRefresh();
	}

	// 딸린 애들
	kForEach(qwCtrl* w, _ctls)
	{
		if (childrefresh && !w->NeedRefresh())
			w->SetRefresh();

		if (w->CanSize() && w->HasAnchor())
		{
			// 앵커가 달려 있는데...
			// 어카지???
		}

		if (w->IsVisible() && !w->OnUpdate(adv))
			break;
	}

	return true;
}

//
void qwPanel::OnDraw()
{
	// 배경
	if (CanFill())
	{
		if (HasShadow())
		{
			_shed->DrawFillRect(tpl::Rect(_client.left + 5, _client.bottom, _client.right, _client.bottom + 5), _color_shadow);
			_shed->DrawFillRect(tpl::Rect(_client.right, _client.top + 5, _client.right + 5, _client.bottom + 5), _color_shadow);
		}

		_shed->DrawFillRect(_client, _bg.res, _bg.tex);
	}

	// 딸린 애들
	if (_ctls.IsHave())
	{
		// 역순으로 그림
		for (auto it = _ctls.Last();; --it)
		{
			qwCtrl* w = *it;

			if (w->IsVisible())
				w->OnDraw();

			if (it == _ctls.First())
				break;
		}
	}

	// 외곽선
	if (HasBorder())
		_shed->DrawEmptyRect(_client, _color_border);

	//
	qwCtrl::OnDraw();
}

//
const qbWidgetResource& qwPanel::GetResource(qgWidgetElement nth)
{
	if (nth == QGWELM_PANEL_BACKGROUND)
		return _bg.res;

	return super_type::GetResource(nth);
}

//
void qwPanel::SetBackground(qgTexture* tex)
{
	if (tex != _bg.tex)
	{
		kobj_unload(_bg.tex);
		_bg.tex = tex;
		kobj_load(tex);
	}
}

//
bool qwPanel::SetResource(qgWidgetElement nth, const qbWidgetResource& res)
{
	if (nth == QGWELM_PANEL_BACKGROUND)
	{
		_bg.res = res;
		return true;
	}

	return super_type::SetResource(nth, res);
}

//
qwCtrl* qwPanel::GetControl(const char* name)
{
	k_return_value_if_fail(name, NULL);

	kForEach(qwCtrl* w, _ctls)
	{
		if (w->GetName().CompareTo(name, true) == 0)
			return w;

		if (!w->IsContainer())
			continue;

		qbWidgetContainer* ctnr = w->GetContainer();
		w = ctnr->GetControl(name);

		if (w)
			return w;
	}

	return NULL;
}

//
qwCtrl* qwPanel::FindControl(kint id)
{
	kForEach(qwCtrl* w, _ctls)
	{
		if (w->GetId() == id)
			return w;

		if (!w->IsContainer())
			continue;

		qbWidgetContainer* ctnr = w->GetContainer();
		w = ctnr->FindControl(id);

		if (w)
			return w;
	}

	return NULL;
}

//
qwCtrl* qwPanel::GetControlNth(kint nth)
{
	return (ksize_t)nth < (ksize_t)_ctls.Count() ? _ctls[nth] : NULL;
}

//
kint qwPanel::IndexControlOf(qwCtrl* cx)
{
	k_return_value_if_fail(cx, -1);

	return _ctls.Contains(cx);
}

//
bool qwPanel::AddControl(qwCtrl* cx)
{
	k_return_value_if_fail(cx, false);
	k_return_value_if_fail(cx->GetShed() == _shed, false);

	// 컨테이너 금지
	k_return_value_if_fail(!cx->IsContainer(), false);

	// 검사 함
	qwCtrl* parent = cx->GetParent();

	if (parent)
	{
		if (parent == this)
		{
			// 부모가 자기면 더할 필요 없음
			return true;
		}

		kint nth = _ctls.Contains(cx);

		if (nth >= 0)
			return false;
	}

	// 창고에서 뺌
	_shed->UnsafeRemoveControl(cx);

	// 넣기
	if (parent)
	{
		if (!parent->IsContainer())
		{
			// 이말은 뭐냐하면 리스트의 스크롤같이 하부 컨트롤이라는 것을 의미함
			return false;
		}

		qbWidgetContainer* ctnr = parent->GetContainer();
		k_assert_0(ctnr != NULL);

		cx->Load();
		ctnr->UnsafeRemoveControl(cx);
	}

	// 진짜 넣기
	qwPanel::UnsafeAddControl(cx);

	return true;
}

//
bool qwPanel::RemoveControl(qwCtrl* cx)
{
	k_return_value_if_fail(cx, false);
	k_return_value_if_fail(cx->GetParent() == this, false);

	return qwPanel::UnsafeRemoveControl(cx);
}

//
void qwPanel::UnsafeAddControl(qwCtrl* cx)
{
	cx->SetParent(this);
	cx->SetDepth(++_depth);
	cx->SetRefresh();

	_ctls.Add(cx);
	qwPanel::SortControls(cx);

	cx->Load();
}

//
bool qwPanel::UnsafeRemoveControl(qwCtrl* cx)
{
	kint nth = _ctls.Contains(cx);

	if (nth < 0)
		return false;

	_ctls.RemoveAt(nth);

	cx->SetParent(NULL);
	cx->Unload();

	return true;
}

//
void qwPanel::ClearControls()
{
	kForEach(qwCtrl* w, _ctls)
	{
		w->SetParent(NULL);
		w->Unload();
	}

	_ctls.Clear();
}

//
void qwPanel::SortControls(qwCtrl* primary)
{
	// 자세한 구현은 qgWidgetShedImpl::SortControls() 함수 참조

	if (primary == *_ctls.Begin())
		return;

	//
	kint count = _ctls.Count();
	_depth = count;

	SortWidgets(count, _ctls.Data());

	kForEach(qwCtrl* w, _ctls)
		w->SetDepth(count--);
}

//
qwCtrl* qwPanel::AddDivide(kint id, kint x, kint y, kint size)
{
	qwDivide* c = (qwDivide*)_shed->CreateControl(QGW_DIVIDE, id, tpl::Rect(x, y, x, y + size), this);

	c->Unload();

	return c;
}

//
qwCtrl* qwPanel::AddLabel(kint id, kint x, kint y, kint w, kint h, const char* text)
{
	qwLabel* c = (qwLabel*)_shed->CreateControl(QGW_LABEL, id, tpl::Rect(x, y, x + w, y + h), this);

	if (text)
		c->SetText(text);

	c->Unload();

	return c;
}

//
qwCtrl* qwPanel::AddButton(kint id, kint x, kint y, kint w, kint h, const char* text)
{
	qwButton* c = (qwButton*)_shed->CreateControl(QGW_BUTTON, id, tpl::Rect(x, y, x + w, y + h), this);

	if (text)
		c->SetText(text);

	c->Unload();

	return c;
}

//
qwCtrl* qwPanel::AddProgress(kint id, kint x, kint y, kint w, kint h, kint minv, kint maxv)
{
	qwProgress* c = (qwProgress*)_shed->CreateControl(QGW_PROGRESS, id, tpl::Rect(x, y, x + w, y + h), this);

	c->SetRange(tpl::Point(minv, maxv));

	c->Unload();

	return c;
}

//
qwCtrl* qwPanel::AddScroll(kint id, kint x, kint y, kint h, kint size)
{
	qwScroll* c = (qwScroll*)_shed->CreateControl(QGW_SCROLL, id, tpl::Rect(x, y, x + size, y + h), this);

	c->Unload();

	return c;
}

//
qwCtrl* qwPanel::AddList(kint id, kint x, kint y, kint w, kint h)
{
	qwList* c = (qwList*)_shed->CreateControl(QGW_LIST, id, tpl::Rect(x, y, x + w, y + h), this);

	c->Unload();

	return c;
}

//
qwCtrl* qwPanel::AddCombo(kint id, kint x, kint y, kint w, kint h, kint droplen)
{
	qwCombo* c = (qwCombo*)_shed->CreateControl(QGW_COMBO, id, tpl::Rect(x, y, x + w, y + h), this);

	if (droplen > 0)
		c->SetDropLength(droplen);

	c->Unload();

	return c;
}

//
qwCtrl* qwPanel::AddTextLine(kint id, kint x, kint y, kint w, kint h, const char* text)
{
	qwTextLine* c = (qwTextLine*)_shed->CreateControl(QGW_TEXTLINE, id, tpl::Rect(x, y, x + w, y + h), this);

	if (text)
		c->SetText(text);

	c->Unload();

	return c;
}

//
qwCtrl* qwPanel::AddPanel(kint id, kint x, kint y, kint w, kint h)
{
	qwPanel* c = (qwPanel*)_shed->CreateControl(QGW_PANEL, id, tpl::Rect(x, y, x + w, y + h), this);

	c->Unload();

	return c;
}

//
qwCtrl* qwPanel::PickControl(kint x, kint y)
{
	x -= _client.left;
	y -= _client.top;

	kForEach(qwCtrl* w, _ctls)
	{
		if (!w->IsAlive())
			continue;

		if (w->TestPick(x, y))
			return w;
	}

	return NULL;
}

//
void qwPanel::SetControl(qwCtrl* w, qgWidgetStatus status)
{
	switch ((ksize_t)status)
	{
		case QGWS_SELECT:
			k_return_if_fail(w != _wselect);

			if (_wselect)
				_wselect->SetStatus(_wselect == _wover ? QGWS_OVER : QGWS_NORMAL);

			_wselect = w;

			if (w)
				w->SetStatus(QGWS_SELECT);

			break;

		case QGWS_OVER:
			if (_wover && _wover != _wselect)
				_wover->SetStatus(QGWS_NORMAL);

			_wover = w;

			if (w && w != _wselect)
				w->SetStatus(QGWS_OVER);

			break;
	}
}

//
bool qwPanel::OnMouseMove(kint x, kint y, const tpl::Point& relative, kushort state)
{
	bool ret = true;
	qwCtrl* pick = NULL;

	if (_wselect)
	{
		if (!_wselect->OnMouseMove(x, y, relative, state))
			ret = false;
	}

	// 집기
	if (ret)
	{
		pick = PickControl(x, y);

		if (pick)
		{
			if (_wover != pick)
				SetControl(pick, QGWS_OVER);

			if (_wselect != pick && !pick->OnMouseMove(x, y, relative, state))
				ret = false;
		}
	}

	if (!pick)
		SetControl(NULL, QGWS_OVER);

	return true;
}

//
bool qwPanel::OnMouseDown(kint x, kint y, kushort button)
{
	qwCtrl* pick = _wover ? _wover : PickControl(x, y);

	if (pick)
	{
		_wactive = pick;

		if (button == QIM_LEFT || pick->IsContainer())
			SetControl(pick, QGWS_SELECT);

		pick->SetDepth(++_depth);
		SortControls(pick);

		if (!pick->OnMouseDown(x, y, button))
			return false;
	}

	return true;
}

//
bool qwPanel::OnMouseUp(kint x, kint y, kushort button)
{
	bool ret = true;

	if (_wselect)
	{
		if (!_wselect->OnMouseUp(x, y, button))
			ret = false;
	}

	qwCtrl* pick = PickControl(x, y);

	if (_wselect && _wselect == pick)
	{
		// 현재 선택과 놓인 위치가 같으면
		if (button == QIM_LEFT)
		{
			SetControl(NULL, QGWS_SELECT);

			if (pick->IsAccept() || pick->IsCancel())
			{
				if (pick->IsAccept())
				{
					// 음.. 이벤트
				}
				else if (pick->IsCancel())
				{
					// 닫음
					if (_shed->TestModal(this))
						_shed->SetModal(NULL);
				}
			}
		}
		else
		{
			if (pick->IsContainer())
				SetControl(NULL, QGWS_SELECT);
		}
	}
	else
	{
		// 현재 선택과 눌린 위치가 다르다
		SetControl(NULL, QGWS_SELECT);

		if (pick)
		{
			if (!pick->OnMouseUp(x, y, button))
				ret = false;
		}
	}

	return ret;
}

//
bool qwPanel::OnMouseDouble(kint x, kint y, kushort button)
{
	qwCtrl* pick =
		_wover ? _wover :
		_wselect ? _wselect : PickControl(x, y);

	if (pick)
	{
		if (!pick->OnMouseDouble(x, y, button))
			return false;
	}

	return true;
}

//
bool qwPanel::OnMouseWheel(kshort delta)
{
	qwCtrl* pick =
		_wover ? _wover :
		_wselect ? _wselect : NULL; // PickControl(x, y);

	if (pick)
	{
		if (!pick->OnMouseWheel(delta))
			return false;
	}

	return true;
}

//
bool qwPanel::OnKeyDown(kbyte key, kbyte sub, kuint ch, bool repeat, kushort state)
{
	qwCtrl* pick = _wselect ? _wselect : _wactive;

	if (pick)
	{
		if (!pick->OnKeyDown(key, sub, ch, repeat, state))
			return false;
	}

	return true;
}

//
bool qwPanel::OnKeyUp(kbyte key, kbyte extend, kushort state)
{
	qwCtrl* pick = _wselect ? _wselect : _wactive;

	if (pick)
	{
		if (!pick->OnKeyUp(key, extend, state))
			return false;
	}

	return true;
}

//
bool qwPanel::OnChar(kint ch, bool repeat)
{
	qwCtrl* pick = _wselect ? _wselect : _wactive;

	if (pick)
	{
		if (!pick->OnChar(ch, repeat))
			return false;
	}

	return true;
}

#endif	// _QG_ENABLE_WIDGET
